package controller;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;

import common.Enums.DAOType;
import common.Exceptions.DAOException;
import common.Utils.CommonUtils;

import DAO.DAOFactory;
import DAO.SessionDAO;

import model.*;

public class BaseServlet extends HttpServlet 
{
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
	{
		invokeMethod(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		invokeMethod(request, response);
	}
	
	protected void clearCache(HttpServletRequest request, HttpServletResponse response)
	{
		SessionDAO.getInstance().clearCache();
	}
	
	protected void loadBCs(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException 
	{
		Gson gson =  CommonUtils.createGsonInstance(response); 
		
		try
		{
			response.getWriter().write(gson.toJson(SessionDAO.getInstance().getLoadedBCs()));
		}
		catch(Exception e)
		{
			String errorType = "ERROR";
			
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson(errorType));
		}
	}
	
	protected void loadBcData(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		System.out.println(new Date() + "- " + getClass() + "\n- INFO: Loading BC related data...");
		
		BusinessCase bc = null;
		String bcID = request.getParameter("bcID").toString();
		
		if(bcID != null)
		{
			try 
			{
				SessionDAO.getInstance().clearCache();
				DAOFactory daoFactory = DAOFactory.getDAOFactory(DAOType.MYSQL);
				
				bc = SessionDAO.getInstance().getLoadedBC(UUID.fromString(bcID));
				if(bc == null) //It means that, for some reason, the BC has not been saved in cache yet. So a search on the database is required. 
					bc = daoFactory.getBcDAO().getByID(UUID.fromString(bcID));

				if(bc.getSolution() == null)
				{
					Solution sol = daoFactory.getSolutionDAO().getByID(bc.getSolID());
					bc.setSolution(sol);
				}
				
				for(MethodApplication metApp : daoFactory.getMetAppDAO().getAllByBcID(bc.getID()))
					SessionDAO.getInstance().addMethodApplication(metApp); //Sets all the used BC's components into cache.
				
				SessionDAO.getInstance().setCachedBC(bc); 
				
				System.out.println(new Date() + "- " + getClass() + "\n- INFO: The BC has been loaded successufly. BC name: " + bc.getName() + ", Bc ID: " + bc.getID());
			}
			catch (DAOException e) 
			{
				StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
				String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
				SessionDAO.getInstance().showError(location, e.getMessage(), e);
			} 
		}
	}
	
	/**
	 * This method is responsible for invoking another method, dynamically. 
	 * @param request
	 * @param response
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private void invokeMethod(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		String comando = request.getParameter("comando");
		
		System.out.println("BaseServlet " + comando);
		System.out.println(this.getClass());
 		
		try 
		{
			//Array that contains all the necessary parameters to track down the instance method
			Class<?> partypes[] = new Class[2];
			partypes[0] = HttpServletRequest.class;
			partypes[1] = HttpServletResponse.class;

			//Obtaining the corresponding method
			Class<? extends BaseServlet> cls = this.getClass();
			Method meth = cls.getDeclaredMethod(comando, partypes);

			//Parameters that were read by the BaseServlet (requisition) 
			Object arglist[] = new Object[2];
			arglist[0] = request;
			arglist[1] = response;

			//Method invoke
			meth.invoke(this, arglist);
		} 
		catch (Exception e) 
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			request.setAttribute("Error", e.getMessage());
			
			request.getRequestDispatcher("/webPages/errorPage.jsp").forward(request, response);
		}
	}
}
